package com.shiguiwu.springmybatis.spring.spel;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.Date;

/**
 * @description: SpEl表达式
 * @author: stone
 * @date: Created by 2022/8/10 17:12
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.spel
 * <p>
 * 1）创建解析器：SpEL使用ExpressionParser接口表示解析器，提供SpelExpressionParser默认实
 * 现；
 * 2）解析表达式：使用ExpressionParser的parseExpression来解析相应的表达式为Expression对象。
 * 3）构造上下文：准备比如变量定义等等表达式需要的上下文数据。
 * 4）求值：通过Expression接口的getValue方法根据上下文获得表达式值。
 */
@Slf4j
public class SpElTests {
    public static ExpressionParser parser = new SpelExpressionParser();

    public static void main(String[] args) throws Exception {
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression("('Hello' + ' World').concat(#end)");
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("end", "!!");

        log.info("解析的值是 ==> {}", expression.getValue(context));

        //baseExpression();

        //calculateAndRelationAndLogicExpression();

        //classExpression();

        //instanceExpression();

        //variableExpression();

        //functionExpression();

        //setExpression();

        //getPropertyAndSafeExpression();

        //getSpringBeanExpression();

        templateExpression();

    }


    //###########################################基本表达式###############################################../z

    /**
     * 字面量表达式
     */
    public static void baseExpression() {
        String s1 = parser.parseExpression("'Hello World!'").getValue(String.class);
        log.info("字符串类 ===> {}", s1);

        int intP = parser.parseExpression("1").getValue(Integer.class);
        log.info("int类型的表达式 ===> {}", intP);

        Long lo = parser.parseExpression("1L").getValue(Long.class);
        log.info("long类型的表达式 ===> {}", lo);

        Float aFloat = parser.parseExpression("1.2223").getValue(Float.class);
        log.info("float类型的表达式 ===> {}", aFloat);

        Double aDouble = parser.parseExpression("3.432d").getValue(Double.class);
        log.info("double 类型的表达式 ===> {}", aDouble);

        Boolean aTrue = parser.parseExpression("true").getValue(Boolean.class);
        log.info("boolean类型的变量 ===> {}", aTrue);

        Object aNull = parser.parseExpression("null").getValue(Object.class);
        log.info("引用类型 ===> {}", aNull);

    }

    /**
     * 运算表达式
     * 关系表达式
     */
    public static void calculateAndRelationAndLogicExpression() {
        Integer integer1 = parser.parseExpression("4+3+3-3").getValue(Integer.class);
        Integer integer2 = parser.parseExpression("4%3").getValue(Integer.class);
        Integer integer3 = parser.parseExpression("2^4").getValue(Integer.class);
        log.info("加减运算 ===> {},除法运算 ===> {}, 幂运算 ===> {}", integer1, integer2, integer3);
        Boolean value = parser.parseExpression("1 > 2").getValue(Boolean.class);
        Boolean value1 = parser.parseExpression("1 between {1,2}").getValue(Boolean.class);

        log.info("关系大小运算 ==> {},区间运算 ==> {}", value, value1);

        Boolean value2 = parser.parseExpression("1 > 2 && true").getValue(Boolean.class);
        Boolean value3 = parser.parseExpression("1>2 || true").getValue(Boolean.class);
        Boolean value4 = parser.parseExpression("2>1 and !false").getValue(Boolean.class);

        log.info("逻辑运算 ==> {} ,或运算 ==> {} ,英文运算 ==> {}", value2, value3, value4);
    }


    /**
     * 类表达式
     */
    public static void classExpression() {
        //访问系统包
        Class<String> aClass = parser.parseExpression("T(String)").getValue(Class.class);
        //访问自定义类
        Class<SpElTests> tests = parser.parseExpression("T(com.shiguiwu.springmybatis.spring.spel.SpElTests)").getValue(Class.class);
        //访问静态属性
        Integer value = parser.parseExpression("T(Integer).MAX_VALUE").getValue(Integer.class);
        //访问静态方法
        Integer value1 = parser.parseExpression("T(Integer).parseInt('1')").getValue(Integer.class);

        log.info("访问系统类 ===> {},访问自定义类 ===> {},访问静态属性 ===> {},访问静态方法 ===> {}",
                aClass, tests, value, value1);
    }


    public static void instanceExpression() {
        //字符串实例
        String value = parser.parseExpression("new String('shiguiwu')").getValue(String.class);
        //日期实例
        Date value1 = parser.parseExpression("new java.util.Date()").getValue(Date.class);

        //支持instance of
        Boolean value2 = parser.parseExpression("'shiguiwu' instanceof T(String)").getValue(Boolean.class);

        log.info("字符串实例输出 ===> {},日期实例 ===> {},支持instanceof ===> {}", value, value1, value2);
    }

    /**
     * 定义变量及引用
     */
    public static void variableExpression() {
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("name", "shiguiwu");
        context.setVariable("age", "18");

        //获取变量
        String value = parser.parseExpression("#name").getValue(context, String.class);
        Integer value1 = parser.parseExpression("#age").getValue(context, Integer.class);

        //构造root对象
        context = new StandardEvaluationContext("我是root对象");
        //获取root对象

        String value2 = parser.parseExpression("#root").getValue(context, String.class);
        //获取当前上下文对象
        String value3 = parser.parseExpression("#this").getValue(context, String.class);

        log.info("获取变量的值 {}，{}，获取root对象 {}，获取上下文对象 {}", value, value1, value2, value3);
    }

    /**
     * 自定义函数
     * 目前只支持类静态方法注册为自定义函数；SpEL使用StandardEvaluationContext的registerFunction方
     * 法进行注册自定义函数，其实完全可以使用setVariable代替，两者其实本质是一样的；
     */
    public static void functionExpression() throws NoSuchMethodException {
        StandardEvaluationContext context = new StandardEvaluationContext();
        Class<SpElTests> aClass = SpElTests.class;
        Method method = aClass.getMethod("add", int.class, int.class);
        context.registerFunction("add", method);
        String value = parser.parseExpression("#add('2','4')").getValue(context, String.class);

        log.info("调用函数为 ===> {}", value);
    }

    public static String add(int x, int y) {
        return "" + (x + y);
    }


    /**
     * 表达式赋值
     */
    public static void setExpression() {
        Pet pet = new Pet("小猫咪");
        //为root对象的时候
        EvaluationContext context = new StandardEvaluationContext(pet);
        parser.parseExpression("#root.name").setValue(context, "小猪佩奇");

        log.info("为root对象的时候赋值 ===> {}", pet);
        //为变量的时候
        context = new StandardEvaluationContext();
        context.setVariable("pet", pet);
        parser.parseExpression("#pet.name").setValue(context, "乔治");
        log.info("为变量的时候赋值 ===> {}", pet);


    }

    @Data
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    private static class Pet {
        private String name;



    }


    /**
     * 对象属性存取及安全导航表达式
     * (对象|属性)?.属性
     */
    public static void getPropertyAndSafeExpression() {

        EvaluationContext context = new StandardEvaluationContext();
        Person person = new Person();
        context.setVariable("person", person);
        String value = "";
        try {
            value = parser.parseExpression("#person.pet.name").getValue(context, String.class);

        } catch (Exception e) {
            log.info("出错了。。。。。。。。");

        }
        value = parser.parseExpression("#person?.pet?.name").getValue(context, String.class);
        log.info("导航表达式 ===> {}",value);
        person.setPet(new Pet("小猫咪"));

        value = parser.parseExpression("#person?.pet?.name").getValue(context, String.class);
        log.info("导航表达式 有值的情况===> {}",value);


    }

    @Data
    @ToString
    private static class Person {
        private Pet pet;


    }


    /**
     * SpEL支持使用“@”符号来引用Bean，在引用Bean时需要使用BeanResolver接口实现来查找Bean，
     * Spring提供BeanFactoryResolver实现。
     */
    public static void getSpringBeanExpression() {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        Person person = new Person();
        person.setPet(new Pet("小奶猪"));
        factory.registerSingleton("person", person);
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setBeanResolver(new BeanFactoryResolver(factory));

        Person value = parser.parseExpression("@person").getValue(context, Person.class);
        log.info("获取spring bean ===> {}", value);
    }


    /**
     * 模板表达式就是由字面量与一个或多个表达式块组成
     */
    public static void templateExpression() {
        //解析模板上下文
        ParserContext context = new TemplateParserContext("${", "}");

        //表达式
        Expression expression = parser.parseExpression("我是 ${#name}，今年 ${#age}岁。", context);

        //计算上下文
        EvaluationContext evaluationContext = new StandardEvaluationContext();
        evaluationContext.setVariable("name","小猪佩奇");
        evaluationContext.setVariable("age", "18");
        String value = expression.getValue(evaluationContext, String.class);
        log.info("模板表达式 ===> {}", value);

    }



}
